package com.web.startup;

import com.service.user.AdministratorService;
import com.service.user.CustomerService;
import com.web.filter.SiteMeshFilter;
import com.web.mySecurity.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: lxf
 * Date: 2016/3/17
 * Time: 17:31
 * To change this template use File | Settings | File Templates.
 */
@Configuration
@EnableWebSecurity
public class CustomSecurityConfig extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected String getDispatcherWebApplicationContextSuffix() {
        return "dispatcher";
    }

    @Override
    protected void afterSpringSecurityFilterChain(ServletContext servletContext) {
        FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("characterEncodingFilter", CharacterEncodingFilter.class);
        encodingFilter.setInitParameter("encoding", "UTF-8");
        encodingFilter.setInitParameter("forceEncoding", "true");
        encodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");

        FilterRegistration.Dynamic siteMeshFilter = servletContext.addFilter("siteMeshFilter", SiteMeshFilter.class);
        siteMeshFilter.setInitParameter("excludedPages", "/swagger-ui.html");
        siteMeshFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new StandardPasswordEncoder("MD5");
    }

    @Autowired
    private CustomerService customerService;

    @Configuration
    @Order(1)
    public static class FrontendWebSecurityConfigureAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private MyValidCodeProcessingFilter myValidCodeProcessingFilter;

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http.csrf().disable().requestMatchers()
                    .antMatchers("/", "/index/**", "/public/**", "/aop/**", "/lxf/**", "/user/**", "/js/**", "/thy/**", "/websocket/**", "/rest/**", "/spring/**", "/test", "/painter", "/log4jmonitor/**", "/refuse", "/huawei/**", "/xg**", "/excutor/**")
                    .and().exceptionHandling().accessDeniedPage("/deny")
                    .and().authorizeRequests()    //授权请求
//                    .antMatchers("/xg**").authenticated()
//                    .antMatchers("/excutor/**").access("isAuthenticated() and hasAuthority('XG_MANAGEMENT')")
                    .antMatchers("/**").permitAll()   //允许任何权限
//                    .antMatchers("/public/**", "/user/login", "/user/logout", "/aop/**", "/websocket/**", "/thy/**", "/js/**", "/rest/**", "/spring/**", "/test", "/painter", "/log4jmonitor/**").permitAll()   //允许任何权限
                    .anyRequest().authenticated()               //需要认证的请求
                    .and()
                    .addFilterBefore(myValidCodeProcessingFilter, UsernamePasswordAuthenticationFilter.class)
                    .formLogin()
                    .loginPage("/user/login")
                    .and()
                    .rememberMe()
                    .tokenValiditySeconds(2419200)      // 4周内有效
                    .key("lxfKey")      // 私钥默认为 SpringSecured
                    .and()
                    .logout()
                    .logoutUrl("/user/logout")
                    .logoutSuccessUrl("/user/login");
        }

    }

    @Configuration
    public static class BackedWebSecurityConfigureAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private AdministratorService administratorService;
        @Autowired
        private PasswordEncoder passwordEncoder;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().requestMatchers()
                    .antMatchers("/admin/**")
                    .and().exceptionHandling().accessDeniedPage("/deny")
                    .and().authorizeRequests()    //授权请求
                    .antMatchers("/db/**").access("hasRole('admin') and hasRole('dba')")   //只允许同时拥有admin和dba权限
                    .antMatchers("/admin/**").authenticated()
                    .anyRequest().access("isAuthenticated() and principal.isAdministrator()")
                    .and()
                    .formLogin()
                    .loginPage("/admin/login")
                    .permitAll()
                    .defaultSuccessUrl("/admin/manager")
                    .and()
                    .rememberMe()
                    .tokenValiditySeconds(2419200)      // 4周内有效
                    .key("lxfAdminKey")      // 私钥默认为 SpringSecured
                    .and()
                    .logout()
                    .logoutUrl("/admin/logout")
                    .logoutSuccessUrl("/admin/login");
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(administratorService).passwordEncoder(passwordEncoder);
        }
    }

    @Bean
    public CustomLogoutSuccessHandle myLogoutSuccessHandle() {
        return new CustomLogoutSuccessHandle();
    }

    @Bean
    public CustomLogoutHandle myLogoutHandle() {
        return new CustomLogoutHandle();
    }


    /*@Bean      security 3 and use loginEntry
    public RequestUriDirectUrlResolver forendLoginEntry() {
        RequestUriDirectUrlResolver requestUriDirectUrlResolver = new RequestUriDirectUrlResolver();
        requestUriDirectUrlResolver.setPattern("/forend");
        requestUriDirectUrlResolver.setDirectUrl("/forend/login");
        return requestUriDirectUrlResolver;
    }

    @Bean
    public MultipleAuthenticationLoginEntry multipleAuthenticationLoginEntry() {
        MultipleAuthenticationLoginEntry multipleAuthenticationLoginEntry = new MultipleAuthenticationLoginEntry();
        multipleAuthenticationLoginEntry.setDefaultLoginUrl("/forend/login");
        List<DirectUrlResolver> list = new ArrayList<>();
        list.add(forendLoginEntry());
        multipleAuthenticationLoginEntry.setDirectUrlResolvers(list);
        return multipleAuthenticationLoginEntry;
    }

    @Bean
    public MultipleAuthenticationProcessingFilter multipleAuthenticationProcessingFilter(AuthenticationManager authenticationManager) {
        MultipleAuthenticationProcessingFilter processingFilter = new MultipleAuthenticationProcessingFilter("/login/check");
        List<AuthenticationTokenResolver> list = new ArrayList<>();
        list.add(frontAuthenticationTokenResolver());
        processingFilter.setTokenResolvers(list);
        processingFilter.setAuthenticationManager(authenticationManager);
        processingFilter.setAuthenticationSuccessHandler(successHandler());
        processingFilter.setAuthenticationFailureHandler(failureHandler());
        return processingFilter;
    }

    @Bean
    public FrontAuthenticationTokenResolver frontAuthenticationTokenResolver() {
        FrontAuthenticationTokenResolver frontAuthenticationTokenResolver = new FrontAuthenticationTokenResolver();
        frontAuthenticationTokenResolver.setParameterName("token");
        frontAuthenticationTokenResolver.setParameterValue("forend");
        return frontAuthenticationTokenResolver;
    }

    @Bean
    public MultipleAuthenticationFailureHandler failureHandler() {
        MultipleAuthenticationFailureHandler failureHandler = new MultipleAuthenticationFailureHandler();
        List<DirectUrlResolver> list = new ArrayList<>();
        list.add(forendAuthenticationFailureUrlResolver());
        failureHandler.setResolvers(list);
        return failureHandler;
    }

    @Bean
    public MultipleAuthenticationSuccessHandler successHandler() {
        MultipleAuthenticationSuccessHandler successHandler = new MultipleAuthenticationSuccessHandler();
        successHandler.setAlwaysUseDefaultTargetUrl(true);
        List<DirectUrlResolver> list = new ArrayList<>();
        list.add(forendAuthenticationSuccessUrlResolver());
        successHandler.setResolvers(list);
        return successHandler;
    }

    @Bean(name = "forendAuthenticationSuccessUrlResolver")
    public RequestParameterDirectUrlResolver forendAuthenticationSuccessUrlResolver() {
        RequestParameterDirectUrlResolver requestParameterDirectUrlResolver = new RequestParameterDirectUrlResolver();
        requestParameterDirectUrlResolver.setParameterName("token");
        requestParameterDirectUrlResolver.setPattern("forend");
        requestParameterDirectUrlResolver.setDirectUrl("/forend/login/success");
        return requestParameterDirectUrlResolver;
    }

    @Bean(name = "forendAuthenticationFailureUrlResolver")
    public RequestParameterDirectUrlResolver forendAuthenticationFailureUrlResolver() {
        RequestParameterDirectUrlResolver requestParameterDirectUrlResolver = new RequestParameterDirectUrlResolver();
        requestParameterDirectUrlResolver.setParameterName("token");
        requestParameterDirectUrlResolver.setPattern("forend");
        requestParameterDirectUrlResolver.setDirectUrl("/forend/login?error=1");
        return requestParameterDirectUrlResolver;
    }

    @Bean
    public FrontAuthenticationProvider frontAuthenticationProvider() {
        return new FrontAuthenticationProvider();
    }*/

    @Bean(name = "frontAuthenticationProvider")
    public MyAuthenticationProvider frontAuthenticationProvider() {
        MyAuthenticationProvider myAuthenticationProvider = new MyAuthenticationProvider();
        myAuthenticationProvider.setUserDetailsService(customerService);
        myAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return myAuthenticationProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        List<AuthenticationProvider> list = new ArrayList<>();
        list.add(frontAuthenticationProvider());
        AuthenticationManager authenticationManager = new ProviderManager(list);
        return authenticationManager;
    }

    @Bean
    public MyValidCodeProcessingFilter myValidCodeProcessingFilter(AuthenticationManager authenticationManager) {
        MyValidCodeProcessingFilter filter = new MyValidCodeProcessingFilter();
        filter.setAuthenticationManager(authenticationManager);
        filter.setAuthenticationSuccessHandler(frontAuthenticationSuccessHandler());
        filter.setAuthenticationFailureHandler(frontAuthenticationFailureHandler());
        return filter;
    }

    @Bean
    public FrontAuthenticationFailureHandler frontAuthenticationFailureHandler() {
        return new FrontAuthenticationFailureHandler("/user/login");
    }

    @Bean
    public FrontAuthenticationSuccessHandler frontAuthenticationSuccessHandler() {
        return new FrontAuthenticationSuccessHandler("/xg");
    }

    /*@Bean
    public ExceptionTranslationFilter exceptionTranslationFilter(MyAuthenticationEntryPoint myAuthenticationEntryPoint) {
        ExceptionTranslationFilter filter = new ExceptionTranslationFilter(myAuthenticationEntryPoint);
        return filter;
    }*/

    @Bean
    public MyAuthenticationEntryPoint myAuthenticationEntryPoint() {
        return new MyAuthenticationEntryPoint("/user/login");
    }

}
